/*******************************************************\
|* Author: Trevor Sundberg
\*******************************************************/

// Header protection
#pragma once
#ifndef SKUGO_FRAMEWORK_HPP
#define SKUGO_FRAMEWORK_HPP

// Includes
#include "SkugoTypes.hpp"
#include "SkugoConnection.hpp"
#include "SkugoEventHandler.hpp"
#include "SkugoPacketRouter.hpp"
#include "SkugoPlugin.hpp"
#include "SkugoConnection.hpp"
#include <vector>
#include <string>

// The Skugo class encompasses all of the Skugo framework
namespace Skugo
{
  // Using directives
  using std::vector;
  using std::string;

  // Forward declarations
  class IHost;
  class IPacketRouter;
  class IPluginContainer;
  class IConnection;

  // A client basically just stores data
  class Client
  {
  public:
    // Constructor
    Client(IConnection* connection);

    // Store the connection
    IConnection* const Connection;
    
    // The plugin container contains the list of all local plugins
    PluginContainer* const LocalPlugins;

    // Store the created packet router
    PacketRouter* const Router;

    // A userdata field that can be set to anything by the user.
    void* UserData;

    // Checks if the client is locally connected.
    bool IsLocal();

  private:

    // Assignment and copy should not be allowed
    Client(const Client&);
    Client& operator=(const Client&);
  };

  // The framework starts and stops the external communication
  class Framework
  {
  public:
    
    // Tries to limit all skugo plugins to a given amount of time per update.
    // This field can be adjusted, but is meant to keep the host running smoothly.
    static const float TimeLimitPerUpdateMs;
    
    // Get if the editor is running locally or not
    bool GetIsLocal();
    
    // The default port that we'll connect to.
    static const unsigned short DefaultPort = 8000;

    // Notify a user when a client connects.
    EventHandler<Client> OnClientConnected;

    // Notify a user when a client disconnects.
    EventHandler<Client> OnClientDisconnected;

    // An event that occurs every time the framework is updated.
    EventHandler<void> OnUpdate;
    
    // Get the singleton instance of the framework class
    static Framework* GetInstance();
    
    // Start the framework
    static void Start(string projectName, int argc, char* argv[], unsigned short port = DefaultPort);

    // Stop the framework (the entire connection)
    void Stop();

    // Updating the framework will pump all incoming messages (this is required!)
    void Update();

  private:

    // Get rid of assignment and copy
    Framework& operator =(const Framework&);
    Framework(const Framework&);

    // A privatized constructor (so that the only way to access the framework is through 'GetInstance').
    Framework();

    // Send the name of the project to the current client.
    void SendProjectName(Client* client);

  private:

    // Whether or not we were locally run.
    bool IsLocal;

    // A pointer to the framework instance.
    static Framework* Instance;
    
    // The amount of allowed time this frame (can roll over)!
    float CurrentAllowedTime;
    
    // A host is responsible for establishing connections to the external tool.
    IHost* Host;

    // Store a list of all the clients.
    vector<Client*> Clients;

    // The name of the project (typically this gets used to identify configurations).
    string ProjectName;
  };
}

// End header protection
#endif
